﻿using System;
using TwlNet;
using TwlPhy;
using System.Collections.Generic;

/// <summary>
/// 同步
/// </summary>
public class SyncMoveUtils
{
    private static int HEAD_LEN = 18;//包头长度
    private static short HEAD_FIX = 0x71ab;//包头占位

    /// <summary>
    /// knockState = 0 撞墙 1正常移动 2停止移动
    /// </summary>
    /// <param name="roleId"></param>
    /// <param name="knockState"></param>
    public static void syncMove(long roleId, int knockState = 1)
    {
        BaseEntity role = EntityMgr.getRole<BaseEntity>(roleId);
        if (role != null)
        {
            //停止移动 直接同步当前位置给服务器 服务器做更新位置 再广播
            //其他移动 客户端计算预测位置给服务器 服务器做模拟移动 再广播
            Vector2 addMove = Vector2.zero;
            if (knockState != 2)
            {
                float validDis = 0;//有效移动距离
                float dst = role.speed * Physics2D.logicFrame * Physics2D.syncIntervalFrame;//期望移动距离 10帧移动距离
                bool isKnock = Physics2D.moveCast(role.DyBox, role.moveDir, dst, ref validDis);// Physics2D.isCollision(role.DyBox, role.moveDir, dst, ref validDis);
                addMove.x = validDis * role.moveDir.x;
                addMove.y = validDis * role.moveDir.y;
                //Logger.log(string.Format("dst {0} validDis {1}", dst, validDis));
                knockState = isKnock ? 0 : 1;
            }
            pb.SyncPlayerPosReq msg = new pb.SyncPlayerPosReq();
            msg.playerId = roleId;
            msg.dir = new pb.PBVector2();
            msg.dir.x = (long)(role.moveDir.x * 1000);
            msg.dir.y = (long)(role.moveDir.y * 1000);
            msg.speed = (long)(role.speed * 1000);
            msg.pos = new pb.PBVector3();
            //Logger.log(string.Format("addMove x:{0} y:{1}", addMove.x, addMove.y));
            //Logger.log(string.Format("DyBox x:{0} y:{1}", role.DyBox.centerX, role.DyBox.centerY));
            msg.pos.x = (long)((role.DyBox.centerX + addMove.x) * 1000);
            msg.pos.y = (long)((role.DyBox.centerY + addMove.y) * 1000);
            msg.pos.z = 0;
            msg.utcTime = (long)TimerUtils.getMillTimer();
            msg.isKnock = knockState;
            //Logger.log("给服务器同步移动x  " + msg.pos.x + " y " + msg.pos.y);
            sendMsg<pb.SyncPlayerPosReq>(msg, 103);
            //byte[] data = ProtobufSerializer.Serialize<pb.SyncPlayerPosReq>(msg);
            //int len = data.Length;
            //ByteBuffer buffer = ByteBuffer.Allocate(len + HEAD_LEN);
            //buffer.WriteShort(HEAD_FIX);
            //buffer.WriteShort((short)(HEAD_LEN + len));
            //buffer.WriteShort(103);
            //buffer.WriteLong(roleId);
            //buffer.WriteInt(0);
            //buffer.WriteBytes(data);
            //GameSocket.Instance.Send(buffer);
        }
    }

    /// <summary>
    /// 技能同步
    ///同步一个技能id 和 释放技能位置
    /// </summary>
    /// <param name="roleId"></param>
    /// <param name="skillId"></param>
    public static void syncSkill(long roleId, int skillId)
    {
        BaseEntity role = EntityMgr.getRole<BaseEntity>(roleId);
        if (role == null)
        {
            return;
        }
        pb.SkillCastMsg msg = new pb.SkillCastMsg();
        msg.playerId = roleId;
        msg.skillId = skillId;
        msg.pos = new pb.PBVector3();
        msg.pos.x = (long)(role.DyBox.centerX * 1000);
        msg.pos.y = (long)(role.DyBox.centerY * 1000);
        msg.pos.z = (long)(role.DyBox.centerZ * 1000);

        sendMsg<pb.SkillCastMsg>(msg, 201);
    }

    /// <summary>
    /// 伤害检测同步
    /// </summary>
    /// <param name="caster"></param>
    /// <param name="lst"></param>
    /// <param name="skillId"></param>
    /// <param name="hitId"></param>
    public static void syncHit(long caster, List<long> lst, int skillId, int hitId)
    {
        BaseEntity role = EntityMgr.getRole<BaseEntity>(caster);
        if (role == null)
        {
            return;
        }
        pb.SkillHitMsg msg = new pb.SkillHitMsg();
        msg.playerId = caster;
        msg.skillId = skillId;
        msg.hitId = hitId;
        msg.pos = new pb.PBVector3();
        msg.pos.x = (long)(role.DyBox.centerX * 1000);
        msg.pos.y = (long)(role.DyBox.centerY * 1000);
        msg.pos.z = (long)(role.DyBox.centerZ * 1000);
        msg.hiters.AddRange(lst);

        sendMsg<pb.SkillHitMsg>(msg, 203);
    }

    private static void sendMsg<T>(T msg, short cmd)
    {
        byte[] data = ProtobufSerializer.Serialize<T>(msg);
        int len = data.Length;
        ByteBuffer buffer = ByteBuffer.Allocate(len + HEAD_LEN);
        buffer.WriteShort(HEAD_FIX);
        buffer.WriteShort((short)(HEAD_LEN + len));
        buffer.WriteShort(cmd);
        buffer.WriteLong(EntityMgr.Instance.mainRoleId);
        buffer.WriteInt(0);
        buffer.WriteBytes(data);
        GameSocket.Instance.Send(buffer);
    }

}

